// Tool Execution Engine Implementation

import {
    ToolExecutionEngine,
    ToolRegistry,
    ToolResult,
    ToolExecutionContext,
    ToolDefinition,
    ErrorCode
} from './interfaces';

/**
 * 工具执行引擎实现类
 */
export class DefaultToolExecutionEngine implements ToolExecutionEngine {
    private registry: ToolRegistry;
    private logger: any;
    private executionCounter: number = 0;

    constructor(registry: ToolRegistry, logger?: any) {
        this.registry = registry;
        this.logger = logger || console;
    }

    /**
     * 执行工具
     */
    async execute(
        toolName: string,
        parameters: Record<string, any>,
        context?: ToolExecutionContext
    ): Promise<ToolResult> {
        const executionId = this.generateExecutionId();
        const startTime = Date.now();

        try {
            this.logger.info(`Starting tool execution: ${toolName}`, { executionId, parameters });

            // 1. 查找工具
            const tool = this.registry.getTool(toolName);
            if (!tool) {
                throw new Error(`Tool '${toolName}' not found`);
            }

            // 2. 检查工具是否启用
            if (!tool.metadata.isEnabled) {
                throw new Error(`Tool '${toolName}' is disabled`);
            }

            // 3. 验证参数
            const validationResult = tool.handler.validate(parameters);
            if (!validationResult.isValid) {
                throw new Error(`Parameter validation failed: ${validationResult.errors.join(', ')}`);
            }

            // 4. 预处理参数
            let processedParams = parameters;
            if (tool.handler.preprocessParameters) {
                const defaultContext: ToolExecutionContext = {
                    workspaceRoot: process.cwd(),
                    environment: process.env as Record<string, string>,
                    timestamp: new Date()
                };
                processedParams = await tool.handler.preprocessParameters(parameters, context || defaultContext);
            }

            // 5. 检查权限
            await this.checkPermissions(tool.definition, processedParams, context);

            // 6. 执行工具
            const result = await this.executeWithTimeout(tool.handler, processedParams, context, tool.definition.timeout);

            // 7. 处理结果
            let finalResult = result;
            if (tool.handler.transformResult) {
                finalResult = await tool.handler.transformResult(result);
            }

            // 8. 更新统计信息
            this.registry.updateCallStats(toolName);

            const duration = Date.now() - startTime;
            this.logger.info(`Tool execution completed: ${toolName}`, { executionId, duration });

            return {
                success: true,
                data: finalResult,
                metadata: {
                    executionTime: duration,
                    timestamp: new Date().toISOString(),
                    toolName: toolName
                }
            };

        } catch (error) {
            const duration = Date.now() - startTime;
            this.logger.error(`Tool execution failed: ${toolName}`, {
                executionId,
                duration,
                error: error instanceof Error ? error.message : `${error}`
            });

            return {
                success: false,
                error: {
                    code: error instanceof Error ? this.getErrorCode(error) : ErrorCode.EXECUTION_FAILED,
                    message: error instanceof Error ? error.message : `${error}`,
                    details: { executionId, duration }
                },
                metadata: {
                    executionTime: duration,
                    timestamp: new Date().toISOString(),
                    toolName: toolName
                }
            };
        }
    }

    /**
     * 检查工具是否可用
     */
    isToolAvailable(toolName: string): boolean {
        const tool = this.registry.getTool(toolName);
        return tool !== null && tool.metadata.isEnabled;
    }

    /**
     * 获取工具定义
     */
    getToolDefinition(toolName: string): ToolDefinition | null {
        const tool = this.registry.getTool(toolName);
        return tool ? tool.definition : null;
    }

    /**
     * 带超时的工具执行
     */
    private async executeWithTimeout(
        handler: any,
        parameters: Record<string, any>,
        context: ToolExecutionContext | undefined,
        timeout: number = 30000
    ): Promise<any> {
        const timeoutPromise = new Promise((_, reject) => {
            setTimeout(() => {
                reject(new Error(`Tool execution timeout after ${timeout}ms`));
            }, timeout);
        });

        const executionPromise = handler.execute(parameters, context || {});

        return Promise.race([executionPromise, timeoutPromise]);
    }

    /**
     * 检查权限
     */
    private async checkPermissions(
        definition: ToolDefinition,
        parameters: Record<string, any>,
        context?: ToolExecutionContext
    ): Promise<void> {
        if (!definition.requiresPermissions || definition.requiresPermissions.length === 0) {
            return;
        }

        const userPermissions = context?.permissions || [];

        for (const requiredPermission of definition.requiresPermissions) {
            if (!userPermissions.includes(requiredPermission)) {
                throw new Error(`Permission denied: ${requiredPermission} is required`);
            }
        }
    }

    /**
     * 生成执行ID
     */
    private generateExecutionId(): string {
        return `exec_${++this.executionCounter}_${Date.now()}`;
    }

    /**
     * 获取错误代码
     */
    private getErrorCode(error: Error): string {
        if (error.message.includes('not found')) {
            return ErrorCode.TOOL_NOT_FOUND;
        }
        if (error.message.includes('validation failed')) {
            return ErrorCode.INVALID_PARAMETERS;
        }
        if (error.message.includes('Permission denied')) {
            return ErrorCode.PERMISSION_DENIED;
        }
        if (error.message.includes('timeout')) {
            return ErrorCode.TIMEOUT;
        }
        if (error.message.includes('disabled')) {
            return ErrorCode.TOOL_DISABLED;
        }
        return ErrorCode.EXECUTION_FAILED;
    }
}
